/**
 * Copyright 2008 - 2009 Pro-Netics S.P.A.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package it.pronetics.madstore.hatom.alfresco.util;

import java.util.ArrayList;
import java.util.List;

import nu.xom.Element;
import nu.xom.Node;
import nu.xom.ParentNode;

/**
 * A class of useful methods made to manage some operations on XOM nodes.
 * 
 * @author Salvatore Incandela
 */

public class XomUtils {

	public static final String DIV = "div";
	public static final String SPAN = "span";
	public static final String ADDRESS = "address";

	/**
	 * This method adds in the passed List all the parents of the passed node.
	 * 
	 * @param node
	 *            Starting Node
	 * @param parents
	 *            List where adding the parents Node of the passed Node.
	 * @return Modified List.
	 */

	public static List<Node> getParents(Node node, List<Node> parents) {
		Node parent = node.getParent();
		if (parent == null) {
			return parents;
		} else {
			parents.add(parent);
			return getParents(parent, parents);
		}
	}

	/**
	 * This method retrieves the lowest common ancestor of the nodes contained
	 * in the passed List.
	 * 
	 * @param nodes
	 *            List of objects Node.
	 * @return (Node) lowest common ancestor.
	 */

	public static Node getLowestCommonAncestor(List<Node> nodes) {
		List<List<Node>> allParents = getAllParents(nodes);
		List<Node> shortestList = removeShortestList(allParents);
		return computeLowestCommonAncestor(allParents, shortestList);
	}

	/**
	 * This method computes the lowest common ancestor.
	 * 
	 * @param allParents
	 * @param shortestList
	 * @return (Node) lowest common ancestor.
	 */

	private static Node computeLowestCommonAncestor(
			List<List<Node>> allParents, List<Node> shortestList) {
		Node lowestCommonAncestor = null;
		for (Node node : shortestList) {
			boolean isLowestCommonAncestor = true;
			for (List<Node> otherList : allParents) {
				isLowestCommonAncestor = isLowestCommonAncestor
						&& otherList.contains(node);
			}
			if (isLowestCommonAncestor) {
				lowestCommonAncestor = node;
				break;
			}
		}
		return lowestCommonAncestor;
	}

	/**
	 * This method retrieves all the parents of the nodes contained in the
	 * passed List.
	 * 
	 * @param nodes
	 *            List of nodes.
	 * @return All parents of the nodes contained in the passed List.
	 */

	private static List<List<Node>> getAllParents(List<Node> nodes) {
		List<List<Node>> allParents = new ArrayList<List<Node>>();
		for (Node node : nodes) {
			List<Node> parents = new ArrayList<Node>();
			allParents.add(getParents(node, parents));
		}
		return allParents;
	}

	/**
	 * This method removes the shortest List in the passed List of List
	 * 
	 * @param allParents
	 *            passed List
	 * @return Removed shortest List
	 */

	private static List<Node> removeShortestList(List<List<Node>> allParents) {
		List<Node> firstList = ((ArrayList<List<Node>>) allParents).get(0);
		int size = firstList.size();
		int index = 0;
		for (int i = 0; i < allParents.size(); i++) {
			List<Node> tempList = allParents.get(i);
			if (tempList.size() < size) {
				index = i;
			}
		}
		return allParents.remove(index);
	}

	/**
	 * This method returns a new Node list with the same nodes of the passed
	 * list without null Object.
	 * 
	 * @param newElements
	 *            List to filter
	 * @return New list without null objects
	 */

	public static List<Node> removeNullsNodes(List<Node> newElements) {
		List<Node> newElementsTemp = new ArrayList<Node>();
		for (Node node : newElements) {
			if (node != null) {
				newElementsTemp.add(node);
			}
		}
		return newElementsTemp;
	}

	/**
	 * This method deletes every Element in the passed List, maintaining the
	 * child of the Element to delete.
	 * 
	 * @param elements
	 */

	public static void deleteElements(List<Element> elements) {
		for (Element toDel : elements) {
			if (toDel != null) {
				ParentNode parent = toDel.getParent();
				Node newChild = toDel.getChild(0);
				newChild.detach();
				parent.replaceChild(toDel, newChild);
			}
		}
	}

}
